package com.cls.system.service.impl;

import com.cls.business.entity.ApplicantInfo;
import com.cls.business.entity.EntrustTopic;
import com.cls.business.entity.ITopic;
import com.cls.business.entity.Topic;
import com.cls.business.mapper.EntrustTopicMapper;
import com.cls.business.mapper.TopicMapper;
import com.cls.business.service.IApplicantInfoService;
import com.cls.common.enums.DictEnum;
import com.cls.system.entity.*;
import com.cls.system.mapper.ExpertMapper;
import com.cls.system.service.IRoleService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.cls.common.authentication.ShiroRealm;
import com.cls.common.entity.MyConstant;
import com.cls.common.entity.QueryRequest;
import com.cls.common.exception.MyException;
import com.cls.common.utils.MyUtil;
import com.cls.common.utils.Md5Util;
import com.cls.system.mapper.UserMapper;
import com.cls.system.service.IUserDataPermissionService;
import com.cls.system.service.IUserRoleService;
import com.cls.system.service.IUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author WeiMaomao
 */
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final IUserRoleService userRoleService;
    private final IUserDataPermissionService userDataPermissionService;
    private final ShiroRealm shiroRealm;
    private final IRoleService roleService;
    private final IApplicantInfoService applicantInfoService;
    private final ExpertMapper expertMapper;
    private final TopicMapper topicMapper;
    private final EntrustTopicMapper entrustTopicMapper;

    @Override
    public User findByName(String username) {
        return this.baseMapper.findByName(username);
    }

    @Override
    public PageInfo<User> findUserDetailList(User user, QueryRequest request) {
       /* if (StringUtils.isNotBlank(user.getCreateTimeFrom()) &&
                StringUtils.equals(user.getCreateTimeFrom(), user.getCreateTimeTo())) {
            user.setCreateTimeFrom(user.getCreateTimeFrom() + " 00:00:00");
            user.setCreateTimeTo(user.getCreateTimeTo() + " 23:59:59");
        }*/
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<User> userDetailList = this.baseMapper.findUserDetail(user);
        PageInfo pageInfo = new PageInfo(userDetailList);
        return pageInfo;
    }

    @Override
    public User findUserDetailList(String username) {
        User param = new User();
        param.setUsername(username);
        List<User> users = this.baseMapper.findUserDetail(param);
        return CollectionUtils.isNotEmpty(users) ? users.get(0) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLoginTime(String username) {
        User user = new User();
        user.setLastLoginTime(new Date());
        this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getUsername, username));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createUser(User user) {
        user.setStatus(User.STATUS_VALID);
        user.setAvatar(User.DEFAULT_AVATAR);
        user.setTheme(User.THEME_BLACK);
        user.setIsTab(User.TAB_OPEN);
        user.setPassword(Md5Util.encrypt(user.getUsername(), User.DEFAULT_PASSWORD));
        user.setPersonTypeCode(DictEnum.PERSON_TYPE_ADMIN.getCode());
        save(user);
        // 保存用户角色
        String[] roles = user.getRoleId().split(StringPool.COMMA);
        setUserRoles(user, roles);
        // 保存用户数据权限关联关系
        String[] deptIds = StringUtils.splitByWholeSeparatorPreserveAllTokens(user.getDeptIds(), StringPool.COMMA);
        if (ArrayUtils.isNotEmpty(deptIds)) {
            setUserDataPermissions(user, deptIds);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUsers(String[] userIds) {
        List<String> list = Arrays.asList(userIds);
        // 删除用户
        this.removeByIds(list);
        // 删除关联角色
        this.userRoleService.deleteUserRolesByUserId(list);
        // 删除关联数据权限
        this.userDataPermissionService.deleteByUserIds(userIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) {
        String username = user.getUsername();
        // 更新用户
        user.setPassword(null);
        user.setUsername(null);
        updateById(user);

        String[] userId = {String.valueOf(user.getUserId())};
        this.userRoleService.deleteUserRolesByUserId(Arrays.asList(userId));
        String[] roles = StringUtils.splitByWholeSeparatorPreserveAllTokens(user.getRoleId(), StringPool.COMMA);
        setUserRoles(user, roles);

        userDataPermissionService.deleteByUserIds(userId);
        String[] deptIds = StringUtils.splitByWholeSeparatorPreserveAllTokens(user.getDeptIds(), StringPool.COMMA);
        if (ArrayUtils.isNotEmpty(deptIds)) {
            setUserDataPermissions(user, deptIds);
        }

        User currentUser = MyUtil.getCurrentUser();
        if (StringUtils.equalsIgnoreCase(currentUser.getUsername(), username)) {
            shiroRealm.clearCache();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(String[] usernames) {
        Arrays.stream(usernames).forEach(username -> {
            User user = new User();
            user.setPassword(Md5Util.encrypt(username, User.DEFAULT_PASSWORD));
            this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void regist(String username, String password) {
        User user = new User();
        user.setPassword(Md5Util.encrypt(username, password));
        user.setUsername(username);
        user.setCreateTime(new Date());
        user.setStatus(User.STATUS_VALID);
        user.setSex(User.SEX_UNKNOW);
        user.setAvatar(User.DEFAULT_AVATAR);
        user.setTheme(User.THEME_BLACK);
        user.setIsTab(User.TAB_OPEN);
        user.setPersonTypeCode(DictEnum.PERSON_TYPE_ADMIN.getCode());
        user.setDescription("注册用户");
        this.save(user);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registFront(String username, String password, String email) {
        User user = new User();
        user.setPassword(Md5Util.encrypt(username, password));
        user.setUsername(username);
        user.setCreateTime(new Date());
        user.setStatus(User.STATUS_VALID);
        user.setSex(User.SEX_UNKNOW);
        user.setAvatar(User.DEFAULT_AVATAR);
        user.setEmail(email);
        user.setTheme(User.THEME_BLACK);
        user.setIsTab(User.TAB_OPEN);
        user.setDescription("注册用户");
        user.setPersonTypeCode(DictEnum.PERSON_TYPE_REGISTER.getCode());
        this.save(user);

        Role byName = roleService.findByName(MyConstant.REGISTER_ROLE_NAME);
        UserRole ur = new UserRole();
        ur.setUserId(user.getUserId());
        ur.setRoleId(byName.getRoleId());
        this.userRoleService.save(ur);
        //创建申请人信息数据
        ApplicantInfo applicantInfo = new ApplicantInfo();
        applicantInfo.setEmail(email);
        applicantInfo.setUserId(user.getUserId());
        applicantInfoService.save(applicantInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(String username, String password) {
        User user = new User();
        user.setPassword(Md5Util.encrypt(username, password));
        user.setModifyTime(new Date());
        this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getUsername, username));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAvatar(String username, String avatar) {
        User user = new User();
        user.setAvatar(avatar);
        this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getUsername, username));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTheme(String username, String theme, String isTab) {
        User user = new User();
        user.setTheme(theme);
        user.setIsTab(isTab);
        user.setModifyTime(new Date());
        this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getUsername, username));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProfile(User user) {
        user.setUsername(null);
        user.setRoleId(null);
        user.setPassword(null);
        if (isCurrentUser(user.getId())) {
            updateById(user);
        } else {
            throw new MyException("您无权修改别人的账号信息！");
        }
    }

    private void setUserRoles(User user, String[] roles) {
        Arrays.stream(roles).forEach(roleId -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getUserId());
            userRole.setRoleId(Long.valueOf(roleId));
            userRoleService.save(userRole);
        });
    }

    private void setUserDataPermissions(User user, String[] deptIds) {
        Arrays.stream(deptIds).forEach(deptId -> {
            UserDataPermission permission = new UserDataPermission();
            permission.setDeptId(Long.valueOf(deptId));
            permission.setUserId(user.getUserId());
            userDataPermissionService.save(permission);
        });
    }

    private boolean isCurrentUser(Long id) {
        User currentUser = MyUtil.getCurrentUser();
        return currentUser.getUserId().equals(id);
    }

    @Override
    @Transactional
    public void createExpertUsers(List<Expert> experts, ITopic iTopic) {
        for (Expert one : experts) {
            registerOneExpert(one);
        }
        if (Objects.nonNull(iTopic)) {
            if (DictEnum.ANNUAL.getCode().equals(iTopic.getTopicClassifyCode())) {
                Topic topic = new Topic();
                topic.setTopicId(iTopic.getTopicId());
                topic.setStatusTypeCode(DictEnum.PLAN_EXPERT.getCode());
                topicMapper.updateById(topic);
            } else if(DictEnum.ENTRUST.getCode().equals(iTopic.getTopicClassifyCode())){
                EntrustTopic entrustTopic = new EntrustTopic();
                entrustTopic.setTopicId(iTopic.getTopicId());
                entrustTopic.setStatusTypeCode(DictEnum.PLAN_EXPERT.getCode());
                entrustTopicMapper.updateById(entrustTopic);
            }else if(DictEnum.UNLIMITED.getCode().equals(iTopic.getTopicClassifyCode())){
                EntrustTopic entrustTopic = new EntrustTopic();
                entrustTopic.setTopicId(iTopic.getTopicId());
                entrustTopic.setStatusTypeCode(DictEnum.PLAN_EXPERT.getCode());
                entrustTopicMapper.updateById(entrustTopic);

                Topic topic = new Topic();
                topic.setTopicId(iTopic.getTopicId());
                topic.setStatusTypeCode(DictEnum.PLAN_EXPERT.getCode());
                topicMapper.updateById(topic);
            }
        }
    }

    /**
     * 密码重置
     *
     * @param userId
     */
    @Override
    public void pwdReset(String userId) {
        User user = this.getById(userId);
        user.setPassword(Md5Util.encrypt(user.getUsername(), MyConstant.INIT_PWD));
        this.updateById(user);
    }

    /**
     * 注册一个专家用户
     *
     * @param expert
     */
    @Override
    public void registerOneExpert(Expert expert) {
        //如果当前手机号存在用户则不创建
        String mobile = expert.getMobile();
        User byName = this.findByName(mobile);
        if (byName != null) {
            return;
        }
        registerExpert(expert);
    }

    /**
     * 专家分配用户
     *
     * @param expert
     */
    @Override
    public void expertUser(Expert expert, ExpertUserVO expertUserVO) {
        //如果当前手机号存在用户则不创建
        String mobile = expert.getMobile();
        User byName = this.findByName(mobile);
        if (byName != null) {
            return;
        }
        registerExpertUser(expert, expertUserVO);
    }

    private void registerExpert(Expert expert) {
        User user = new User();
        String mobile = expert.getMobile();
        String password = "123456";
        if (mobile != null && mobile.length() > 10) {
            password = mobile.substring(3, 9);
        }
        user.setPassword(Md5Util.encrypt(expert.getMobile(), password));
        user.setUsername(expert.getMobile());
        user.setCreateTime(new Date());
        user.setStatus(User.STATUS_VALID);
        user.setSex(User.SEX_UNKNOW);
        user.setAvatar(User.DEFAULT_AVATAR);
        user.setMobile(expert.getMobile());
        user.setTheme(User.THEME_BLACK);
        user.setIsTab(User.TAB_OPEN);
        user.setDescription("专家用户");
        user.setPersonTypeCode(DictEnum.PERSON_TYPE_EXPERT.getCode());
        this.save(user);

        Role byName = roleService.findByName(MyConstant.EXPERT_ROLE_NAME);
        UserRole ur = new UserRole();
        ur.setUserId(user.getUserId());
        ur.setRoleId(byName.getRoleId());
        this.userRoleService.save(ur);
        //创建申请人信息数据
        expert.setUserId(user.getUserId());
        expertMapper.updateById(expert);
    }

    private void registerExpertUser(Expert expert, ExpertUserVO expertUserVO) {
        User user = new User();
        user.setPassword(Md5Util.encrypt(expertUserVO.getUserName(), expertUserVO.getPassword()));
        user.setUsername(expertUserVO.getUserName());
        user.setCreateTime(new Date());
        user.setStatus(User.STATUS_VALID);
        user.setSex(User.SEX_UNKNOW);
        user.setAvatar(User.DEFAULT_AVATAR);
        user.setMobile(expert.getMobile());
        user.setTheme(User.THEME_BLACK);
        user.setIsTab(User.TAB_OPEN);
        user.setDescription("专家用户");
        user.setPersonTypeCode(DictEnum.PERSON_TYPE_EXPERT.getCode());
        this.save(user);

        Role byName = roleService.findByName(MyConstant.EXPERT_ROLE_NAME);
        UserRole ur = new UserRole();
        ur.setUserId(user.getUserId());
        ur.setRoleId(byName.getRoleId());
        this.userRoleService.save(ur);
        //创建申请人信息数据
        expert.setUserId(user.getUserId());
        expertMapper.updateById(expert);
    }
}
